Loading Necessary Packages

Reading in Dataframes

# Community data wide format
cover.wide <- read.csv("../../Data/cover_wide_tradeoffs.csv")
# Site attributes
site.attr <- read.csv("../../Data/comb-by-plot-clim-soil-diversity-02-Aug-2019.csv")

Subsetting datasets to attribute and community matrices

Fitting RRPP models to each site

output_list <- list()
counter <- 1

sitenames = unique(attr.mat$site_code)
sitenames = sitenames[!(sitenames %in% c("doane.us", "pape.de", "sevi.us"))]

# For all unique sites selected
for(sites in sitenames){

  print(paste(counter,":", sites))

  # Subset to a single site
  com.subset <- cover.mat[attr.mat$site_code == sites,]

  # Remove all zero columns
  com.subset <- com.subset[,colSums(com.subset) > 0]

  # Pull out relevant plot attributes for each site
  attr.subset <- data.frame(attr.mat) %>%
    filter(site_code == sites) %>%
    mutate(year_trt = as.factor(year_trt),
           plot = as.factor(plot),
           block = as.factor(block))

  # Check that these two matrices are the same size
  expect_true(nrow(attr.subset) == nrow(com.subset))
  expect_true(nrow(attr.subset) > 0)

  mod_rrpp <- lm.rrpp(com.subset ~ year_trt + trt_K_num + trt_P_num + trt_N_num + block,
                      data = attr.subset,
                      SS.type = "III",
                      iter = num_iter,
                      print.progress = FALSE)

  # Saving ouput
  output = list(siteinfo = attr.subset,
                aovtable = anova(mod_rrpp, effect.type = "F",
                                  error = c("Residuals", "Residuals", "Residuals",
                                            "Residuals", "Residuals")),
                specscores = coef(mod_rrpp))

  output_list[[counter]] = output
  counter = counter + 1
}
storagelist <- list()
for(i in 1:length(output_list)){
  anovatab = bind_cols(site = as.character(unique(output_list[[i]]$siteinfo$site_code)),
            data.frame(matrix(output_list[[i]]$aovtable$table$`Pr(>F)`, nrow = 1)))
  colnames(anovatab)[2:ncol(anovatab)] =   rownames(output_list[[i]]$aovtable$table)
  storagelist[[i]] = anovatab
}
write.csv(x = bind_rows(storagelist),
  "../../Data/tradeoffs_RRPP_Pvals.csv")
storagelist <- list()
for(i in 1:length(output_list)){
  sp_scores = data.frame(output_list[[i]]$specscores[grep("trt_", rownames(output_list[[i]]$specscores)),])
  tomatch = c(4:10)
  # sp_scores = sp_scores[grepl(paste(tomatch, collapse = "|"), rownames(sp_scores)),]
  spectab = bind_cols(site = rep(unique(output_list[[i]]$siteinfo$site_code), nrow(sp_scores)),
                    trt = rownames(sp_scores),
                    sp_scores)
  storagelist[[i]] = spectab %>% mutate(trt = gsub("_num", "", trt))
}
specscores_full = data.frame(bind_rows(storagelist))
specscores_full[is.na(specscores_full)] = 0
write.csv(specscores_full, "../../Data/tradeoffs_specscores.csv")

Calculate dot-product of pairwise correlations

Given these estimated parameters, we can calculate the correlation between species responses to different pairs of nutrient treatments through the dot-product of the fitted vectors between treatments within a site.

After calculating this dot-product, the distributions of each set correlation scores can be seen in histograms below:

# Normalization function -- squared sums of vector = 1
scalar1 <- function(x) {x / sqrt(sum(x^2))}

# Defining dot-product function
dotprod <- function(x, normalize = TRUE){

  # First, select the appropriate treatment and remove columns that aren't plant response
  N_vec <- x %>% filter(trt == "trt_N") %>% select(-trt, -site)
  P_vec <- x %>% filter(trt == "trt_P") %>% select(-trt, -site)
  K_vec <- x %>% filter(trt == "trt_K") %>% select(-trt, -site)

  N_change <- sqrt(sum(N_vec^2))
  P_change <- sqrt(sum(P_vec^2))
  K_change <- sqrt(sum(K_vec^2))

  # If normalizing, run the normalize function on each vector
  if(normalize == TRUE){
    N_vec <- scalar1(N_vec)
    P_vec <- scalar1(P_vec)
    K_vec <- scalar1(K_vec)
  }

  # Generate output dataframe of dot products (pracma::dot function)
  output = data.frame(NP = pracma::dot(as.numeric(N_vec), as.numeric(P_vec)),
                      NK = pracma::dot(as.numeric(N_vec), as.numeric(K_vec)),
                      PK = pracma::dot(as.numeric(P_vec), as.numeric(K_vec)),
                      N_change = N_change,
                      P_change = P_change,
                      K_change = K_change)

  return(output)

}

# Run over our dataset
dotoutput = specscores_full %>% group_by(site) %>%
  do(dotprod(.))

# Load permANOVA p-value output
site_pvals = read.csv("../../Data/tradeoffs_RRPP_Pvals.csv", header = TRUE, stringsAsFactors = FALSE)

# Join all together (sites, treatments, dot-product pairs, perMANOVA p-values)
dot_full = left_join(site_pvals %>% select(-Total, -Residuals), dotoutput) %>%
  select(-X) %>%
  rename("trt_K" = "trt_K_num", "trt_P" =  "trt_P_num", "trt_N" = "trt_N_num")

# Write final data product
write.csv(x = dot_full, "../../Data/dot_full.csv")

Plotting correlation between different vectors of change

dot_full <- read.csv("../../Data/dot_full.csv")
p1 = dot_full %>% # filter(trt_N < .05 & trt_P < .05) %>%
  ggplot(aes(x = NP,
             fill = trt_N < 0.05 & trt_P < .05)) +
  geom_histogram(aes(y = ..count..), color = "black", alpha = .5, position = "identity", bins = 25,
                 data = dot_full %>% filter(trt_N < .05 & trt_P < .05)) +
  geom_histogram(aes(y = -..count..), color = "black", alpha = .5, position = "identity", bins = 25,
                 data = dot_full %>% filter(!(trt_N < .05 & trt_P < .05))) +
  xlim(-1, 1) +
  ggtitle("N - P Correlation") +
  guides(fill = FALSE) +
  scale_y_continuous(limits = c(-4,4), breaks = seq(-6, 6, by = 2), labels = abs( seq(-6, 6, by = 2))) +
  geom_text(aes(x = -.25, y = 3.5), label = "Both vectors significant (p < 0.05)", color = "turquoise4") +
  geom_text(aes(x = -.25, y = -3.5), label = "=< 1 vectors significant (p < 0.05)", color = "tomato2")
p2 = dot_full %>% # filter(trt_N < .05 & trt_K < .05) %>%
  ggplot(aes(x = NK,
             fill = trt_N < 0.05 & trt_K < .05)) +
  geom_histogram(aes(y = ..count..), color = "black", alpha = .5, position = "identity", bins = 25,
                 data = dot_full %>% filter(trt_K < .05 & trt_N < .05)) +
  geom_histogram(aes(y = -..count..), color = "black", alpha = .5, position = "identity", bins = 25, 
                 data = dot_full %>% filter(!(trt_K < .05 & trt_N < .05))) +  
  xlim(-1, 1) +
  ggtitle("N - K Correlation")+
  guides(fill = FALSE) +
  scale_y_continuous(limits = c(-4,4), breaks = seq(-6, 6, by = 2), labels = abs( seq(-6, 6, by = 2)))
p3 = dot_full %>% # filter(trt_K < .05 & trt_P < .05) %>%
  ggplot(aes(x = PK,
             fill = trt_K < 0.05 & trt_P < .05))+
  geom_histogram(aes(y = ..count..), color = "black", alpha = .5, position = "identity", bins = 25,
                 data = dot_full %>% filter(trt_K < .05 & trt_P < .05)) +
  geom_histogram(aes(y = -..count..), color = "black", alpha = .5, position = "identity", bins = 25,
                 data = dot_full %>% filter(!(trt_K < .05 & trt_P < .05))) +
  xlim(-1, 1) +
  ggtitle("P - K Correlation")+
  guides(fill = FALSE)+
  scale_y_continuous(limits = c(-4, 4), breaks = seq(-6, 6, by = 2), labels = abs( seq(-6, 6, by = 2)))
grid.arrange(p1,p2,p3,
             top = textGrob("Site Response Correlations",gp=gpar(fontsize=20,font=3)),
             nrow = 3)

Visualizing Example Communities

rdaFit = function(site){
  com.subset <- data.frame(cover.mat)[attr.mat$site_code == site,]
  
  # Remove all zero columns
  com.subset = com.subset[,colSums(com.subset) > 0]
  
  # Pull out relevant plot attributes for each site
  attr.subset <- data.frame(attr.mat) %>% filter(site_code == site)
  
  # Check that these two matrices are the same size
  expect_true(nrow(attr.subset) == nrow(com.subset))
  
  # Generate and return an NMDS figure
  mod_out <- vegan::metaMDS(com.subset, distance = "euclidean", autotransform = FALSE, try = 50)
  env <- envfit(mod_out, attr.subset %>% select(block, trt_N_num, trt_P_num, trt_K_num) %>% mutate(block = as.factor(block)))

  # Generating GGplot
  ggplot() + 
    geom_point(aes(x = MDS1, y = MDS2), pch = 21, fill = "white", alpha = .5, size = 2,
               data = data.frame(mod_out$points) * attr(mod_out$points, "internalscaling")) +
    geom_segment(aes(x = 0, y = 0, xend = NMDS1, yend = NMDS2), data = data.frame(env$vectors$arrows), size = 2, 
                 arrow = arrow(length = unit(0.5, "cm"), type = "closed")) +
     geom_point(aes(x = NMDS1, y = NMDS2), data = data.frame(env$vectors$arrows), alpha = 0, size = 6) + 
    ggrepel::geom_text_repel(aes(x = NMDS1, y = NMDS2), 
              data = data.frame(env$vectors$arrows), 
              label = gsub("_num", "", rownames(data.frame(env$vectors$arrows))),
              size = 6) +
    ggtitle(site)
}

rdaFit("rook.uk"); ggsave("../../Figures/rook_nmds.pdf", height = 5, width = 5)
rdaFit("bnch.us"); ggsave("../../Figures/bnch_nmds.pdf", height = 5, width = 5)

Summarising communities by functional group abundance

LS0tDQp0aXRsZTogIlIgTm90ZWJvb2siDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQojIyMgTG9hZGluZyBOZWNlc3NhcnkgUGFja2FnZXMNCg0KYGBge3IsIG1lc3NhZ2UgPSBGQUxTRSwgZWNobyA9IEZBTFNFfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KHdhcm5pbmcgPSBGQUxTRSwgbWVzc2FnZSA9IEZBTFNFLGZpZy53aWR0aCA9IDUsIGZpZy5oZWlnaHQgPSAzLjUpDQoNCiMgTG9hZGluZyBuZWNlc3NhcnkgcGFja2FnZXMNCmxpYnJhcnkodGlkeXZlcnNlKSAjIERhdGEgbWFuaXB1bGF0aW9uDQpsaWJyYXJ5KHZlZ2FuKSAjIEdlbmVyYWwgZWNvbG9neSBmdW5jdGlvbnMNCmxpYnJhcnkoZGF0YS50YWJsZSkgIyBGYXN0IHJlYWRpbmcgb2YgZGF0YSB0YWJsZXMNCmxpYnJhcnkodGVzdHRoYXQpICMgVW5pdCB0ZXN0aW5nDQpsaWJyYXJ5KGZhc3REdW1taWVzKSAjIEZhc3QgZ2VuZXJhdGlvbiBvZiBkdW1teSB2YXJpYWJsZXMNCiMgbGlicmFyeShkdHBseXIpICNEcGx5ciBmb3IgZGF0YS50YWJsZQ0KbGlicmFyeShSUlBQKSAjIFJSUFAgZm9yIG11bHRpdmFyaWF0ZSBtb2RlbCBmaXR0aW5naW5zdGENCmxpYnJhcnkoZ3JpZEV4dHJhKQ0KbGlicmFyeShncmlkKQ0KYGBgDQoNCiMjIyBSZWFkaW5nIGluIERhdGFmcmFtZXMNCg0KYGBge3J9DQojIENvbW11bml0eSBkYXRhIHdpZGUgZm9ybWF0DQpjb3Zlci53aWRlIDwtIHJlYWQuY3N2KCIuLi8uLi9EYXRhL2NvdmVyX3dpZGVfdHJhZGVvZmZzLmNzdiIpDQoNCiMgU2l0ZSBhdHRyaWJ1dGVzDQpzaXRlLmF0dHIgPC0gcmVhZC5jc3YoIi4uLy4uL0RhdGEvY29tYi1ieS1wbG90LWNsaW0tc29pbC1kaXZlcnNpdHktMDItQXVnLTIwMTkuY3N2IikNCg0KIyBBbmFseXNpcyBwYXJhbWV0ZXJzDQptaW5feXJfdHJ0IDwtIDUgIyBOdW1iZXIgb2YgeWVhcnMgbWluaW11bSB0byBiZSBpbmNsdWRlZCBpbiBhbmFseXNpcw0KDQojIE51bWJlciBvZiBpdGVyYXRpb25zIGluIFJSUFANCm51bV9pdGVyIDwtIDk5OTkNCg0KYGBgDQoNCiMjIyBTdWJzZXR0aW5nIGRhdGFzZXRzIHRvIGF0dHJpYnV0ZSBhbmQgY29tbXVuaXR5IG1hdHJpY2VzDQoNCmBgYHtyfQ0KIyBDaGVja2luZyB0aGF0IGFsbCBjb3ZlciB2YWx1ZXMgYXJlIG51bWVyaWMNCmNvbHMgPC0gYyhjb2xuYW1lcyhjb3Zlci53aWRlKVstYygxOjYpXSkNCmNvdmVyLndpZGVbLWMoMTo2KV0gPC0gYXBwbHkoY292ZXIud2lkZVstYygxOjYpXSwgTUFSR0lOID0gMiwgRlVOID0gYXMubnVtZXJpYykNCg0KIyBTZXBhcmF0aW5nIGRhdGFmcmFtZSBpbnRvIGNvdmVyIGFuZCBhdHRyaWJ1dGUNCmF0dHIubWF0ID0gY292ZXIud2lkZVssMTo3XSAlPiUgY29sdW1uX3RvX3Jvd25hbWVzKHZhcj0iWCIpDQpjb3Zlci52YWxzID0gZGF0YS5mcmFtZShjb3Zlci53aWRlWywtYygyOjcpXSkgJT4lIGNvbHVtbl90b19yb3duYW1lcyh2YXI9IlgiKQ0KDQojIFNob3VsZCB3ZSBub3JtYWxpemU/DQojIyBOb3JtYWxpemluZyBtaWdodCBiZSBzdGFuZGFyZCBpZiB3ZSdyZSBkZWFsaW5nIGluIHByb3BvcnRpb25zDQojIyBIb3dldmVyLCB3ZSBoYXZlIGEgbWluaW11bSBjb3ZlciB0aHJlc2hvbGQsIHVzdWFsbHkgYWJvdXQgLjUNCiMjIG5vcm1hbGl6aW5nIGluIHRoaXMgY2FzZSBtaWdodCBjYXVzZSBwcm9ibGVtcyBpZiB3ZSBoYXZlIHRvdGFsIGNvdmVyIGluY3JlYXNpbmcNCiMjIHRoaXMgY2FuIGNhdXNlIGxvdy1hYnVuZGFuY2Ugc3BlY2llcyB0byBiZWNvbWUgbGVzcyBhYnVuZGFudCwgZXZlbiBpZiB0aGV5IGFyZQ0KIyMgdGhlIHNhbWUgYWJzb2x1dGUgYWJ1bmRhbmNlIGluIGJvdGggY2FzZXMNCg0KIyBjb3Zlci5tYXQgPSByb3VuZCh2ZWdhbjo6ZGVjb3N0YW5kKGNvdmVyLnZhbHMsIG1ldGhvZCA9ICJ0b3RhbCIpLCAzKQ0KY292ZXIubWF0ID0gY292ZXIudmFscw0KDQojIENyZWF0aW5nIG5ldyBkdW1teSB2YXJpYWJsZXMgdGhhdCByZWZlciB0byBudW1lcmljIHRyZWF0bWVudCBlZmZlY3RzDQphdHRyLm1hdCA9IGR1bW15X2NvbHVtbnMoYXR0ci5tYXQsIHNlbGVjdF9jb2x1bW5zID0gInRydCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICByZW1vdmVfZmlyc3RfZHVtbXkgPSBUUlVFKSAlPiUNCiAgcmVwbGFjZV9uYShsaXN0KHRydF9LID0gMCwgdHJ0X04gPSAwLCB0cnRfUCA9IDApKSAlPiUNCiAgbXV0YXRlKHRydF9LX251bSA9bG9nKGFzLm51bWVyaWModHJ0X0sgKiB5ZWFyX3RydCkgKyAxKSwNCiAgICAgICAgIHRydF9QX251bSA9bG9nKGFzLm51bWVyaWModHJ0X1AgKiB5ZWFyX3RydCkgKyAxKSwNCiAgICAgICAgIHRydF9OX251bSA9bG9nKGFzLm51bWVyaWModHJ0X04gKiB5ZWFyX3RydCkgKyAxKSwNCiAgICAgICAgIHllYXJfdHJ0ID0gbG9nKGFzLm51bWVyaWMoeWVhcl90cnQpICsgMSkpDQoNCiMgU2V0dGluZyB0cmVhdG1lbnQgZWZmZWN0cyB0byB6ZXJvIGZvciB0aGUgZmlyc3QgeWVhciBvZiB0cmVhdG1lbnQNCmF0dHIubWF0JHRydF9LW2F0dHIubWF0JHllYXJfdHJ0ID09IDBdID0gMA0KYXR0ci5tYXQkdHJ0X1BbYXR0ci5tYXQkeWVhcl90cnQgPT0gMF0gPSAwDQphdHRyLm1hdCR0cnRfTlthdHRyLm1hdCR5ZWFyX3RydCA9PSAwXSA9IDANCg0KDQojIENyZWF0aW5nIGRhdGFzZXQgb2Ygc2l0ZXMgdXNlZCBpbiB0aGUgYW5hbHlzaXMNCnNpdGVzX2RmIDwtIGxlZnRfam9pbihhdHRyLm1hdCAlPiUgc2VsZWN0KHNpdGVfY29kZSwgcGxvdCwgeWVhciksIHNpdGUuYXR0ciwgYnkgPSBjKCJzaXRlX2NvZGUiLCAicGxvdCIsICJ5ZWFyIikpICU+JSANCiAgZ3JvdXBfYnkoc2l0ZV9jb2RlKSAlPiUNCiAgc3VtbWFyaXNlKHNpdGVfbmFtZSA9IHVuaXF1ZShzaXRlX25hbWUpLA0KICAgICAgICAgICAgY29udGluZW50ID0gdW5pcXVlKGNvbnRpbmVudCksDQogICAgICAgICAgICBjb3VudHJ5ID0gdW5pcXVlKGNvdW50cnkpLA0KICAgICAgICAgICAgbl95ZWFycyA9IGxlbmd0aCh1bmlxdWUoeWVhcikpLA0KICAgICAgICAgICAgbl9vYnMgPSBuKCksDQogICAgICAgICAgICBmaXJzdF9udXRyaWVudF95ZWFyID0gdW5pcXVlKGZpcnN0X251dHJpZW50X3llYXIpKSAlPiUNCiAgZmlsdGVyKCEoc2l0ZV9jb2RlJWluJSBjKCJkb2FuZS51cyIsICJwYXBlLmRlIiwgInNldmkudXMiKSkpDQoNCndyaXRlLmNzdigiLi4vLi4vRGF0YS90cmFkZW9mZnNfc2VsZWN0ZWRzaXRlcy5jc3YiLA0KICAgICAgICAgIHggPSBzaXRlc19kZikNCg0KIyBDbGVhbmluZyB3b3Jrc3BhY2UNCnJtKGNvdmVyLndpZGUsIGNvdmVyLnZhbHMpDQogICAgICAgICAgICANCndyaXRlLmNzdigiLi4vLi4vRGF0YS90cmFkZW9mZnNfY29tbS5jc3YiLA0KICAgICAgICAgIHggPSBjb3Zlci5tYXQsDQogICAgICAgICAgcm93Lm5hbWVzID0gRkFMU0UpDQoNCndyaXRlLmNzdigiLi4vLi4vRGF0YS90cmFkZW9mZnNfYXR0ci5jc3YiLA0KICAgICAgICAgIHggPSBhdHRyLm1hdCwNCiAgICAgICAgICByb3cubmFtZXMgPSBGQUxTRSkNCmBgYA0KDQojIyMgRml0dGluZyBSUlBQIG1vZGVscyB0byBlYWNoIHNpdGUNCg0KYGBge3J9DQpvdXRwdXRfbGlzdCA8LSBsaXN0KCkNCmNvdW50ZXIgPC0gMQ0KDQpzaXRlbmFtZXMgPSB1bmlxdWUoYXR0ci5tYXQkc2l0ZV9jb2RlKQ0Kc2l0ZW5hbWVzID0gc2l0ZW5hbWVzWyEoc2l0ZW5hbWVzICVpbiUgYygiZG9hbmUudXMiLCAicGFwZS5kZSIsICJzZXZpLnVzIikpXQ0KDQojIEZvciBhbGwgdW5pcXVlIHNpdGVzIHNlbGVjdGVkDQpmb3Ioc2l0ZXMgaW4gc2l0ZW5hbWVzKXsNCg0KICBwcmludChwYXN0ZShjb3VudGVyLCI6Iiwgc2l0ZXMpKQ0KDQogICMgU3Vic2V0IHRvIGEgc2luZ2xlIHNpdGUNCiAgY29tLnN1YnNldCA8LSBjb3Zlci5tYXRbYXR0ci5tYXQkc2l0ZV9jb2RlID09IHNpdGVzLF0NCg0KICAjIFJlbW92ZSBhbGwgemVybyBjb2x1bW5zDQogIGNvbS5zdWJzZXQgPC0gY29tLnN1YnNldFssY29sU3Vtcyhjb20uc3Vic2V0KSA+IDBdDQoNCiAgIyBQdWxsIG91dCByZWxldmFudCBwbG90IGF0dHJpYnV0ZXMgZm9yIGVhY2ggc2l0ZQ0KICBhdHRyLnN1YnNldCA8LSBkYXRhLmZyYW1lKGF0dHIubWF0KSAlPiUNCiAgICBmaWx0ZXIoc2l0ZV9jb2RlID09IHNpdGVzKSAlPiUNCiAgICBtdXRhdGUoeWVhcl90cnQgPSBhcy5mYWN0b3IoeWVhcl90cnQpLA0KICAgICAgICAgICBwbG90ID0gYXMuZmFjdG9yKHBsb3QpLA0KICAgICAgICAgICBibG9jayA9IGFzLmZhY3RvcihibG9jaykpDQoNCiAgIyBDaGVjayB0aGF0IHRoZXNlIHR3byBtYXRyaWNlcyBhcmUgdGhlIHNhbWUgc2l6ZQ0KICBleHBlY3RfdHJ1ZShucm93KGF0dHIuc3Vic2V0KSA9PSBucm93KGNvbS5zdWJzZXQpKQ0KICBleHBlY3RfdHJ1ZShucm93KGF0dHIuc3Vic2V0KSA+IDApDQoNCiAgbW9kX3JycHAgPC0gbG0ucnJwcChjb20uc3Vic2V0IH4geWVhcl90cnQgKyB0cnRfS19udW0gKyB0cnRfUF9udW0gKyB0cnRfTl9udW0gKyBibG9jaywNCiAgICAgICAgICAgICAgICAgICAgICBkYXRhID0gYXR0ci5zdWJzZXQsDQogICAgICAgICAgICAgICAgICAgICAgU1MudHlwZSA9ICJJSUkiLA0KICAgICAgICAgICAgICAgICAgICAgIGl0ZXIgPSBudW1faXRlciwNCiAgICAgICAgICAgICAgICAgICAgICBwcmludC5wcm9ncmVzcyA9IEZBTFNFKQ0KDQogICMgU2F2aW5nIG91cHV0DQogIG91dHB1dCA9IGxpc3Qoc2l0ZWluZm8gPSBhdHRyLnN1YnNldCwNCiAgICAgICAgICAgICAgICBhb3Z0YWJsZSA9IGFub3ZhKG1vZF9ycnBwLCBlZmZlY3QudHlwZSA9ICJGIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlcnJvciA9IGMoIlJlc2lkdWFscyIsICJSZXNpZHVhbHMiLCAiUmVzaWR1YWxzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlJlc2lkdWFscyIsICJSZXNpZHVhbHMiKSksDQogICAgICAgICAgICAgICAgc3BlY3Njb3JlcyA9IGNvZWYobW9kX3JycHApKQ0KDQogIG91dHB1dF9saXN0W1tjb3VudGVyXV0gPSBvdXRwdXQNCiAgY291bnRlciA9IGNvdW50ZXIgKyAxDQp9DQpgYGANCg0KYGBge3J9DQpzdG9yYWdlbGlzdCA8LSBsaXN0KCkNCg0KZm9yKGkgaW4gMTpsZW5ndGgob3V0cHV0X2xpc3QpKXsNCg0KICBhbm92YXRhYiA9IGJpbmRfY29scyhzaXRlID0gYXMuY2hhcmFjdGVyKHVuaXF1ZShvdXRwdXRfbGlzdFtbaV1dJHNpdGVpbmZvJHNpdGVfY29kZSkpLA0KICAgICAgICAgICAgZGF0YS5mcmFtZShtYXRyaXgob3V0cHV0X2xpc3RbW2ldXSRhb3Z0YWJsZSR0YWJsZSRgUHIoPkYpYCwgbnJvdyA9IDEpKSkNCg0KICBjb2xuYW1lcyhhbm92YXRhYilbMjpuY29sKGFub3ZhdGFiKV0gPSAgIHJvd25hbWVzKG91dHB1dF9saXN0W1tpXV0kYW92dGFibGUkdGFibGUpDQoNCiAgc3RvcmFnZWxpc3RbW2ldXSA9IGFub3ZhdGFiDQoNCn0NCg0Kd3JpdGUuY3N2KHggPSBiaW5kX3Jvd3Moc3RvcmFnZWxpc3QpLA0KICAiLi4vLi4vRGF0YS90cmFkZW9mZnNfUlJQUF9QdmFscy5jc3YiKQ0KDQpzdG9yYWdlbGlzdCA8LSBsaXN0KCkNCg0KZm9yKGkgaW4gMTpsZW5ndGgob3V0cHV0X2xpc3QpKXsNCiAgc3Bfc2NvcmVzID0gZGF0YS5mcmFtZShvdXRwdXRfbGlzdFtbaV1dJHNwZWNzY29yZXNbZ3JlcCgidHJ0XyIsIHJvd25hbWVzKG91dHB1dF9saXN0W1tpXV0kc3BlY3Njb3JlcykpLF0pDQoNCiAgdG9tYXRjaCA9IGMoNDoxMCkNCiAgIyBzcF9zY29yZXMgPSBzcF9zY29yZXNbZ3JlcGwocGFzdGUodG9tYXRjaCwgY29sbGFwc2UgPSAifCIpLCByb3duYW1lcyhzcF9zY29yZXMpKSxdDQoNCiAgc3BlY3RhYiA9IGJpbmRfY29scyhzaXRlID0gcmVwKHVuaXF1ZShvdXRwdXRfbGlzdFtbaV1dJHNpdGVpbmZvJHNpdGVfY29kZSksIG5yb3coc3Bfc2NvcmVzKSksDQogICAgICAgICAgICAgICAgICAgIHRydCA9IHJvd25hbWVzKHNwX3Njb3JlcyksDQogICAgICAgICAgICAgICAgICAgIHNwX3Njb3JlcykNCg0KICBzdG9yYWdlbGlzdFtbaV1dID0gc3BlY3RhYiAlPiUgbXV0YXRlKHRydCA9IGdzdWIoIl9udW0iLCAiIiwgdHJ0KSkNCn0NCg0Kc3BlY3Njb3Jlc19mdWxsID0gZGF0YS5mcmFtZShiaW5kX3Jvd3Moc3RvcmFnZWxpc3QpKQ0Kc3BlY3Njb3Jlc19mdWxsW2lzLm5hKHNwZWNzY29yZXNfZnVsbCldID0gMA0Kd3JpdGUuY3N2KHNwZWNzY29yZXNfZnVsbCwgIi4uLy4uL0RhdGEvdHJhZGVvZmZzX3NwZWNzY29yZXMuY3N2IikNCmBgYA0KDQojIyMgQ2FsY3VsYXRlIGRvdC1wcm9kdWN0IG9mIHBhaXJ3aXNlIGNvcnJlbGF0aW9ucw0KDQpHaXZlbiB0aGVzZSBlc3RpbWF0ZWQgcGFyYW1ldGVycywgd2UgY2FuIGNhbGN1bGF0ZSB0aGUgY29ycmVsYXRpb24gYmV0d2VlbiBzcGVjaWVzIHJlc3BvbnNlcw0KdG8gZGlmZmVyZW50IHBhaXJzIG9mIG51dHJpZW50IHRyZWF0bWVudHMgdGhyb3VnaCB0aGUgZG90LXByb2R1Y3Qgb2YgdGhlIGZpdHRlZA0KdmVjdG9ycyBiZXR3ZWVuIHRyZWF0bWVudHMgd2l0aGluIGEgc2l0ZS4NCg0KQWZ0ZXIgY2FsY3VsYXRpbmcgdGhpcyBkb3QtcHJvZHVjdCwgdGhlIGRpc3RyaWJ1dGlvbnMgb2YgZWFjaCBzZXQgY29ycmVsYXRpb24gc2NvcmVzIGNhbiBiZSBzZWVuIGluIGhpc3RvZ3JhbXMgYmVsb3c6DQoNCiogVmFsdWVzIGNsb3NlIHRvIHplcm8gaW5kaWNhdGUgdGhhdCBzcGVjaWVzIHJlc3BvbnNlcyB0byB0d28gdHJlYXRtZW50cyB3aXRoaW4gYSBzaXRlIGFyZSBub3QgY29ycmVsYXRlZCB3aXRoIG9uZSBhbm90aGVyLg0KDQoqIFZhbHVlcyBjbG9zZSB0byBvbmUgb3IgbmVnYXRpdmUgb25lIGluZGljYXRlIHRoYXQgc3BlY2llcyByZXNwb25zZXMgdG8gdHdvIHRyZWF0bWVudHMgd2l0aGluIGEgc2l0ZSBhcmUgaGlnaGx5IHBvc2l0aXZlbHkgb3IgbmVnYXRpdmVseSBjb3JyZWxhdGVkLg0KDQpgYGB7cn0NCiMgTm9ybWFsaXphdGlvbiBmdW5jdGlvbiAtLSBzcXVhcmVkIHN1bXMgb2YgdmVjdG9yID0gMQ0Kc2NhbGFyMSA8LSBmdW5jdGlvbih4KSB7eCAvIHNxcnQoc3VtKHheMikpfQ0KDQojIERlZmluaW5nIGRvdC1wcm9kdWN0IGZ1bmN0aW9uDQpkb3Rwcm9kIDwtIGZ1bmN0aW9uKHgsIG5vcm1hbGl6ZSA9IFRSVUUpew0KDQogICMgRmlyc3QsIHNlbGVjdCB0aGUgYXBwcm9wcmlhdGUgdHJlYXRtZW50IGFuZCByZW1vdmUgY29sdW1ucyB0aGF0IGFyZW4ndCBwbGFudCByZXNwb25zZQ0KICBOX3ZlYyA8LSB4ICU+JSBmaWx0ZXIodHJ0ID09ICJ0cnRfTiIpICU+JSBzZWxlY3QoLXRydCwgLXNpdGUpDQogIFBfdmVjIDwtIHggJT4lIGZpbHRlcih0cnQgPT0gInRydF9QIikgJT4lIHNlbGVjdCgtdHJ0LCAtc2l0ZSkNCiAgS192ZWMgPC0geCAlPiUgZmlsdGVyKHRydCA9PSAidHJ0X0siKSAlPiUgc2VsZWN0KC10cnQsIC1zaXRlKQ0KDQogIE5fY2hhbmdlIDwtIHNxcnQoc3VtKE5fdmVjXjIpKQ0KICBQX2NoYW5nZSA8LSBzcXJ0KHN1bShQX3ZlY14yKSkNCiAgS19jaGFuZ2UgPC0gc3FydChzdW0oS192ZWNeMikpDQoNCiAgIyBJZiBub3JtYWxpemluZywgcnVuIHRoZSBub3JtYWxpemUgZnVuY3Rpb24gb24gZWFjaCB2ZWN0b3INCiAgaWYobm9ybWFsaXplID09IFRSVUUpew0KICAgIE5fdmVjIDwtIHNjYWxhcjEoTl92ZWMpDQogICAgUF92ZWMgPC0gc2NhbGFyMShQX3ZlYykNCiAgICBLX3ZlYyA8LSBzY2FsYXIxKEtfdmVjKQ0KICB9DQoNCiAgIyBHZW5lcmF0ZSBvdXRwdXQgZGF0YWZyYW1lIG9mIGRvdCBwcm9kdWN0cyAocHJhY21hOjpkb3QgZnVuY3Rpb24pDQogIG91dHB1dCA9IGRhdGEuZnJhbWUoTlAgPSBwcmFjbWE6OmRvdChhcy5udW1lcmljKE5fdmVjKSwgYXMubnVtZXJpYyhQX3ZlYykpLA0KICAgICAgICAgICAgICAgICAgICAgIE5LID0gcHJhY21hOjpkb3QoYXMubnVtZXJpYyhOX3ZlYyksIGFzLm51bWVyaWMoS192ZWMpKSwNCiAgICAgICAgICAgICAgICAgICAgICBQSyA9IHByYWNtYTo6ZG90KGFzLm51bWVyaWMoUF92ZWMpLCBhcy5udW1lcmljKEtfdmVjKSksDQogICAgICAgICAgICAgICAgICAgICAgTl9jaGFuZ2UgPSBOX2NoYW5nZSwNCiAgICAgICAgICAgICAgICAgICAgICBQX2NoYW5nZSA9IFBfY2hhbmdlLA0KICAgICAgICAgICAgICAgICAgICAgIEtfY2hhbmdlID0gS19jaGFuZ2UpDQoNCiAgcmV0dXJuKG91dHB1dCkNCg0KfQ0KDQojIFJ1biBvdmVyIG91ciBkYXRhc2V0DQpkb3RvdXRwdXQgPSBzcGVjc2NvcmVzX2Z1bGwgJT4lIGdyb3VwX2J5KHNpdGUpICU+JQ0KICBkbyhkb3Rwcm9kKC4pKQ0KDQojIExvYWQgcGVybUFOT1ZBIHAtdmFsdWUgb3V0cHV0DQpzaXRlX3B2YWxzID0gcmVhZC5jc3YoIi4uLy4uL0RhdGEvdHJhZGVvZmZzX1JSUFBfUHZhbHMuY3N2IiwgaGVhZGVyID0gVFJVRSwgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKQ0KDQojIEpvaW4gYWxsIHRvZ2V0aGVyIChzaXRlcywgdHJlYXRtZW50cywgZG90LXByb2R1Y3QgcGFpcnMsIHBlck1BTk9WQSBwLXZhbHVlcykNCmRvdF9mdWxsID0gbGVmdF9qb2luKHNpdGVfcHZhbHMgJT4lIHNlbGVjdCgtVG90YWwsIC1SZXNpZHVhbHMpLCBkb3RvdXRwdXQpICU+JQ0KICBzZWxlY3QoLVgpICU+JQ0KICByZW5hbWUoInRydF9LIiA9ICJ0cnRfS19udW0iLCAidHJ0X1AiID0gICJ0cnRfUF9udW0iLCAidHJ0X04iID0gInRydF9OX251bSIpDQoNCiMgV3JpdGUgZmluYWwgZGF0YSBwcm9kdWN0DQp3cml0ZS5jc3YoeCA9IGRvdF9mdWxsLCAiLi4vLi4vRGF0YS9kb3RfZnVsbC5jc3YiKQ0KYGBgDQoNCg0KIyMjIFBsb3R0aW5nIGNvcnJlbGF0aW9uIGJldHdlZW4gZGlmZmVyZW50IHZlY3RvcnMgb2YgY2hhbmdlDQoNCmBgYHtyLCBmaWcuaGVpZ2h0ID0gOCwgZmlnLndpZHRoID0gNH0NCmRvdF9mdWxsIDwtIHJlYWQuY3N2KCIuLi8uLi9EYXRhL2RvdF9mdWxsLmNzdiIpDQoNCnAxID0gZG90X2Z1bGwgJT4lICMgZmlsdGVyKHRydF9OIDwgLjA1ICYgdHJ0X1AgPCAuMDUpICU+JQ0KICBnZ3Bsb3QoYWVzKHggPSBOUCwNCiAgICAgICAgICAgICBmaWxsID0gdHJ0X04gPCAwLjA1ICYgdHJ0X1AgPCAuMDUpKSArDQogIGdlb21faGlzdG9ncmFtKGFlcyh5ID0gLi5jb3VudC4uKSwgY29sb3IgPSAiYmxhY2siLCBhbHBoYSA9IC41LCBwb3NpdGlvbiA9ICJpZGVudGl0eSIsIGJpbnMgPSAyNSwNCiAgICAgICAgICAgICAgICAgZGF0YSA9IGRvdF9mdWxsICU+JSBmaWx0ZXIodHJ0X04gPCAuMDUgJiB0cnRfUCA8IC4wNSkpICsNCiAgZ2VvbV9oaXN0b2dyYW0oYWVzKHkgPSAtLi5jb3VudC4uKSwgY29sb3IgPSAiYmxhY2siLCBhbHBoYSA9IC41LCBwb3NpdGlvbiA9ICJpZGVudGl0eSIsIGJpbnMgPSAyNSwNCiAgICAgICAgICAgICAgICAgZGF0YSA9IGRvdF9mdWxsICU+JSBmaWx0ZXIoISh0cnRfTiA8IC4wNSAmIHRydF9QIDwgLjA1KSkpICsNCiAgeGxpbSgtMSwgMSkgKw0KICBnZ3RpdGxlKCJOIC0gUCBDb3JyZWxhdGlvbiIpICsNCiAgZ3VpZGVzKGZpbGwgPSBGQUxTRSkgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gYygtNCw0KSwgYnJlYWtzID0gc2VxKC02LCA2LCBieSA9IDIpLCBsYWJlbHMgPSBhYnMoIHNlcSgtNiwgNiwgYnkgPSAyKSkpICsNCiAgZ2VvbV90ZXh0KGFlcyh4ID0gLS4yNSwgeSA9IDMuNSksIGxhYmVsID0gIkJvdGggdmVjdG9ycyBzaWduaWZpY2FudCAocCA8IDAuMDUpIiwgY29sb3IgPSAidHVycXVvaXNlNCIpICsNCiAgZ2VvbV90ZXh0KGFlcyh4ID0gLS4yNSwgeSA9IC0zLjUpLCBsYWJlbCA9ICI9PCAxIHZlY3RvcnMgc2lnbmlmaWNhbnQgKHAgPCAwLjA1KSIsIGNvbG9yID0gInRvbWF0bzIiKQ0KDQpwMiA9IGRvdF9mdWxsICU+JSAjIGZpbHRlcih0cnRfTiA8IC4wNSAmIHRydF9LIDwgLjA1KSAlPiUNCiAgZ2dwbG90KGFlcyh4ID0gTkssDQogICAgICAgICAgICAgZmlsbCA9IHRydF9OIDwgMC4wNSAmIHRydF9LIDwgLjA1KSkgKw0KICBnZW9tX2hpc3RvZ3JhbShhZXMoeSA9IC4uY291bnQuLiksIGNvbG9yID0gImJsYWNrIiwgYWxwaGEgPSAuNSwgcG9zaXRpb24gPSAiaWRlbnRpdHkiLCBiaW5zID0gMjUsDQogICAgICAgICAgICAgICAgIGRhdGEgPSBkb3RfZnVsbCAlPiUgZmlsdGVyKHRydF9LIDwgLjA1ICYgdHJ0X04gPCAuMDUpKSArDQogIGdlb21faGlzdG9ncmFtKGFlcyh5ID0gLS4uY291bnQuLiksIGNvbG9yID0gImJsYWNrIiwgYWxwaGEgPSAuNSwgcG9zaXRpb24gPSAiaWRlbnRpdHkiLCBiaW5zID0gMjUsIA0KICAgICAgICAgICAgICAgICBkYXRhID0gZG90X2Z1bGwgJT4lIGZpbHRlcighKHRydF9LIDwgLjA1ICYgdHJ0X04gPCAuMDUpKSkgKyAgDQogIHhsaW0oLTEsIDEpICsNCiAgZ2d0aXRsZSgiTiAtIEsgQ29ycmVsYXRpb24iKSsNCiAgZ3VpZGVzKGZpbGwgPSBGQUxTRSkgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gYygtNCw0KSwgYnJlYWtzID0gc2VxKC02LCA2LCBieSA9IDIpLCBsYWJlbHMgPSBhYnMoIHNlcSgtNiwgNiwgYnkgPSAyKSkpDQoNCnAzID0gZG90X2Z1bGwgJT4lICMgZmlsdGVyKHRydF9LIDwgLjA1ICYgdHJ0X1AgPCAuMDUpICU+JQ0KICBnZ3Bsb3QoYWVzKHggPSBQSywNCiAgICAgICAgICAgICBmaWxsID0gdHJ0X0sgPCAwLjA1ICYgdHJ0X1AgPCAuMDUpKSsNCiAgZ2VvbV9oaXN0b2dyYW0oYWVzKHkgPSAuLmNvdW50Li4pLCBjb2xvciA9ICJibGFjayIsIGFscGhhID0gLjUsIHBvc2l0aW9uID0gImlkZW50aXR5IiwgYmlucyA9IDI1LA0KICAgICAgICAgICAgICAgICBkYXRhID0gZG90X2Z1bGwgJT4lIGZpbHRlcih0cnRfSyA8IC4wNSAmIHRydF9QIDwgLjA1KSkgKw0KICBnZW9tX2hpc3RvZ3JhbShhZXMoeSA9IC0uLmNvdW50Li4pLCBjb2xvciA9ICJibGFjayIsIGFscGhhID0gLjUsIHBvc2l0aW9uID0gImlkZW50aXR5IiwgYmlucyA9IDI1LA0KICAgICAgICAgICAgICAgICBkYXRhID0gZG90X2Z1bGwgJT4lIGZpbHRlcighKHRydF9LIDwgLjA1ICYgdHJ0X1AgPCAuMDUpKSkgKw0KICB4bGltKC0xLCAxKSArDQogIGdndGl0bGUoIlAgLSBLIENvcnJlbGF0aW9uIikrDQogIGd1aWRlcyhmaWxsID0gRkFMU0UpKw0KICBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gYygtNCwgNCksIGJyZWFrcyA9IHNlcSgtNiwgNiwgYnkgPSAyKSwgbGFiZWxzID0gYWJzKCBzZXEoLTYsIDYsIGJ5ID0gMikpKQ0KDQpncmlkLmFycmFuZ2UocDEscDIscDMsDQogICAgICAgICAgICAgdG9wID0gdGV4dEdyb2IoIlNpdGUgUmVzcG9uc2UgQ29ycmVsYXRpb25zIixncD1ncGFyKGZvbnRzaXplPTIwLGZvbnQ9MykpLA0KICAgICAgICAgICAgIG5yb3cgPSAzKQ0KYGBgDQoNCmBgYHtyfQ0Kc2lndGFsbHkgPC0gc2l0ZV9wdmFscyAlPiUgc2VsZWN0KHRydF9OX251bSwgdHJ0X1BfbnVtLCB0cnRfS19udW0pICU+JQ0KICBtdXRhdGVfYWxsKGZ1bmN0aW9uKHgpIHggPCAwLjA1KSAlPiUNCiAgbXV0YXRlKE5QID0gdHJ0X05fbnVtID09IDEgJiB0cnRfUF9udW0gPT0gMSwNCiAgICAgICAgIE5LID0gdHJ0X05fbnVtID09IDEgJiB0cnRfS19udW0gPT0gMSwNCiAgICAgICAgIFBLID0gdHJ0X1BfbnVtID09IDEgJiB0cnRfS19udW0gPT0gMSwNCiAgICAgICAgIE5QSyA9IHRydF9OX251bSA9PSAxICYgdHJ0X1BfbnVtID09IDEgJiB0cnRfS19udW0gPT0gMSkgICU+JQ0KICBtdXRhdGVfYWxsKGFzLm51bWVyaWMpICU+JQ0KICByZW5hbWUoIksiID0gInRydF9LX251bSIsDQogICAgICAgICAiTiIgPSAidHJ0X05fbnVtIiwNCiAgICAgICAgICJQIiA9ICJ0cnRfUF9udW0iKSAlPiUNCiAgc3VtbWFyaXNlX2FsbChzdW0pICU+JQ0KICBnYXRoZXIoKQ0KDQpzaWd0YWxseSRrZXkgPSBmYWN0b3Ioc2lndGFsbHkka2V5LCBsZXZlbHMgPSBzaWd0YWxseSRrZXkpDQoNCnNpZ3RhbGx5ICU+JSBnZ3Bsb3QoYWVzKHggPSBrZXksDQogICAgICAgICAgICAgICAgICAgICAgICB5ID0gdmFsdWUgLyBucm93KHNpdGVfcHZhbHMpLA0KICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9IGtleSkpICsNCiAgZ2VvbV9iYXIoYWVzKHkgPSAxKSwgc3RhdCA9ICJpZGVudGl0eSIsIGZpbGwgPSAid2hpdGUiLCBjb2xvciA9ICJibGFjayIpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIGNvbG9yID0gImJsYWNrIikgKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJjYWRldGJsdWUxIiwgImNhZGV0Ymx1ZTMiLCAiY2FkZXRibHVlNCIsICJnb2xkIiwgImdvbGQzIiwgImdvbGQ0IiwgImJyb3duMyIpKSArDQogIHlsaW0oMCwgMSkgKw0KICB5bGFiKCJQcm9wb3J0aW9uIG9mIFNpdGVzIHdoZXJlIFAgPCAwLjA1IikgKw0KICB4bGFiKCJDb2VmZmljaWVudHMiKQ0KYGBgDQoNCiMjIyBWaXN1YWxpemluZyBFeGFtcGxlIENvbW11bml0aWVzDQoNCmBgYHtyLCBoZWlnaHQgPSA0LCB3aWR0aCA9IDN9DQpyZGFGaXQgPSBmdW5jdGlvbihzaXRlKXsNCiAgY29tLnN1YnNldCA8LSBkYXRhLmZyYW1lKGNvdmVyLm1hdClbYXR0ci5tYXQkc2l0ZV9jb2RlID09IHNpdGUsXQ0KICANCiAgIyBSZW1vdmUgYWxsIHplcm8gY29sdW1ucw0KICBjb20uc3Vic2V0ID0gY29tLnN1YnNldFssY29sU3Vtcyhjb20uc3Vic2V0KSA+IDBdDQogIA0KICAjIFB1bGwgb3V0IHJlbGV2YW50IHBsb3QgYXR0cmlidXRlcyBmb3IgZWFjaCBzaXRlDQogIGF0dHIuc3Vic2V0IDwtIGRhdGEuZnJhbWUoYXR0ci5tYXQpICU+JSBmaWx0ZXIoc2l0ZV9jb2RlID09IHNpdGUpDQogIA0KICAjIENoZWNrIHRoYXQgdGhlc2UgdHdvIG1hdHJpY2VzIGFyZSB0aGUgc2FtZSBzaXplDQogIGV4cGVjdF90cnVlKG5yb3coYXR0ci5zdWJzZXQpID09IG5yb3coY29tLnN1YnNldCkpDQogIA0KICAjIEdlbmVyYXRlIGFuZCByZXR1cm4gYW4gTk1EUyBmaWd1cmUNCiAgbW9kX291dCA8LSB2ZWdhbjo6bWV0YU1EUyhjb20uc3Vic2V0LCBkaXN0YW5jZSA9ICJldWNsaWRlYW4iLCBhdXRvdHJhbnNmb3JtID0gRkFMU0UsIHRyeSA9IDUwKQ0KICBlbnYgPC0gZW52Zml0KG1vZF9vdXQsIGF0dHIuc3Vic2V0ICU+JSBzZWxlY3QoYmxvY2ssIHRydF9OX251bSwgdHJ0X1BfbnVtLCB0cnRfS19udW0pICU+JSBtdXRhdGUoYmxvY2sgPSBhcy5mYWN0b3IoYmxvY2spKSkNCg0KICAjIEdlbmVyYXRpbmcgR0dwbG90DQogIGdncGxvdCgpICsgDQogICAgZ2VvbV9wb2ludChhZXMoeCA9IE1EUzEsIHkgPSBNRFMyKSwgcGNoID0gMjEsIGZpbGwgPSAid2hpdGUiLCBhbHBoYSA9IC41LCBzaXplID0gMiwNCiAgICAgICAgICAgICAgIGRhdGEgPSBkYXRhLmZyYW1lKG1vZF9vdXQkcG9pbnRzKSAqIGF0dHIobW9kX291dCRwb2ludHMsICJpbnRlcm5hbHNjYWxpbmciKSkgKw0KICAgIGdlb21fc2VnbWVudChhZXMoeCA9IDAsIHkgPSAwLCB4ZW5kID0gTk1EUzEsIHllbmQgPSBOTURTMiksIGRhdGEgPSBkYXRhLmZyYW1lKGVudiR2ZWN0b3JzJGFycm93cyksIHNpemUgPSAyLCANCiAgICAgICAgICAgICAgICAgYXJyb3cgPSBhcnJvdyhsZW5ndGggPSB1bml0KDAuNSwgImNtIiksIHR5cGUgPSAiY2xvc2VkIikpICsNCiAgICAgZ2VvbV9wb2ludChhZXMoeCA9IE5NRFMxLCB5ID0gTk1EUzIpLCBkYXRhID0gZGF0YS5mcmFtZShlbnYkdmVjdG9ycyRhcnJvd3MpLCBhbHBoYSA9IDAsIHNpemUgPSA2KSArIA0KICAgIGdncmVwZWw6Omdlb21fdGV4dF9yZXBlbChhZXMoeCA9IE5NRFMxLCB5ID0gTk1EUzIpLCANCiAgICAgICAgICAgICAgZGF0YSA9IGRhdGEuZnJhbWUoZW52JHZlY3RvcnMkYXJyb3dzKSwgDQogICAgICAgICAgICAgIGxhYmVsID0gZ3N1YigiX251bSIsICIiLCByb3duYW1lcyhkYXRhLmZyYW1lKGVudiR2ZWN0b3JzJGFycm93cykpKSwNCiAgICAgICAgICAgICAgc2l6ZSA9IDYpICsNCiAgICBnZ3RpdGxlKHNpdGUpDQp9DQoNCnJkYUZpdCgicm9vay51ayIpOyBnZ3NhdmUoIi4uLy4uL0ZpZ3VyZXMvcm9va19ubWRzLnBkZiIsIGhlaWdodCA9IDUsIHdpZHRoID0gNSkNCnJkYUZpdCgiYm5jaC51cyIpOyBnZ3NhdmUoIi4uLy4uL0ZpZ3VyZXMvYm5jaF9ubWRzLnBkZiIsIGhlaWdodCA9IDUsIHdpZHRoID0gNSkNCmBgYA0KDQojIyMgU3VtbWFyaXNpbmcgY29tbXVuaXRpZXMgYnkgZnVuY3Rpb25hbCBncm91cCBhYnVuZGFuY2UNCg0KYGBge3J9DQoNCmBgYA0KDQo=